Modeling Player-character Engagement Poster

The figures from the poster Modeling Player-character Engagement in Single-player Character-Driven Games in ACE Netherlands (2013):

(The paper: /2013/11/15/modeling-player-character-engagement-in-single-player-character-driven-games/)

Probabilities / Game vs. Actual Data
The predicted probabilities to to question I could identify with my player-character: totally disagree (1) — totally agree (5). Black line: predicted probabilities; dotted line: 5%- and 95%-tile players. Blue area: the actual data.

Probabilities by an effect
Probabilities by an effect

Code for producing these figures:

library("ordinal")
library("reshape")
library("ggplot2")
# FUNCTIONS
# from clmm2 tutorial
pred <- function(eta, theta, cat = 1:(length(theta) + 1), inv.link = plogis) {
   Theta <- c(-1000, theta, 1000)
   sapply(cat, function(j) inv.link(Theta[j + 1] - eta) - inv.link(Theta[j] - eta))
}

plot.probabilities2<-function(grid, model, leg, plot=NULL, title="", ylim=NULL) {
   plot <- if(is.null(plot)) ggplot()
   co <- model$coefficients[1:length(model$y.levels)-1]
   pre.mat <- pred(eta=rowSums(grid), theta=co)
   df.pred<-data.frame(pre.mat)
   names(df.pred) <- as.numeric(model$y.levels)
   df<-melt(cbind(df.pred,leg))
   plot1 <- plot + geom_line(data=df, aes(x=variable, y=value, group=leg, shape=leg, color=leg)) +
   ggtitle(title) + ylab("probability") + xlab("")
   if(!is.null(ylim)) {
       plot1 <- plot1 + ylim(0, ylim)
   }
   return(plot1)
}

plot.probabilities3<-function(grid, model, comp.data=NULL, title="", ylim=NULL) {
   co <- model$coefficients[1:length(model$y.levels)-1]
   pre.mat <- pred(eta=rowSums(grid), theta=co)
   df<-data.frame(levels=as.numeric(model$y.levels))
   df["avg"] <- pre.mat[1,]
   df["low"] <- pre.mat[2,]
   df["high"] <- pre.mat[3,]
   if(!is.null(comp.data)) {
      df["freq"] <- summary(comp.data)/sum(summary(comp.data))
   }
   plot1 <- ggplot(data=df)
   if(!is.null(comp.data)) {
      plot1 <- plot1 +
      geom_area(aes(x=levels,y=freq), alpha=0.7, fill="lightblue") +
          geom_point(aes(x=levels, y=freq), colour="lightblue")
   }
   plot1 <- plot1 + geom_line(aes(x=levels, y=avg)) + geom_point(aes(x=levels, y=avg)) +
   ggtitle(title) + ylab("probability") + xlab("") +
   geom_line(aes(x=levels, y=low), lty="dotted") +
   geom_line(aes(x=levels, y=high), lty="dotted")

   if(!is.null(ylim)) {
      plot1 <- plot1 + ylim(0, ylim)
   }
   return(plot1)
}

df <- read.csv(url("http://www.mediafire.com/download/t9d5d97d78qcbpp/story.csv"), sep = ";")
df$game <-  factor(df$game)
df$game <-  factor(df$game)
df$sex <- factor(df$sex, levels=c("Male", "Female"))
df$rpg <- factor(df$rpg, levels=c("not at all", "less frequently", "other", "monthly", "weekly", "daily"))
df$education <- factor(df$education, levels=c("High school", "Other", "Vocational", "College", "Bachelors", "Masters", "Doctoral"))
df$board_games <- factor(df$board_games, levels=c("not at all", "less frequently", "other", "monthly", "weekly", "daily"))
df$videogames <- factor(df$videogames, levels=c("not at all", "less frequently", "other", "monthly", "weekly", "daily"))
df$q4 <- factor(df$q4, ordered = FALSE)
df$q7 <- factor(df$q7, ordered = FALSE)
df$q8 <- factor(df$q8, ordered = FALSE)
df$char_dev <- factor(df$char_dev)
df$play_styles<-factor(df$play_styles)
df$romance <- factor(df$romance)
df$voice <- factor(df$voice)
df$friendship <- factor(df$friendship)
df$appearance <- factor(df$appearance)
# appearance with the best model produces "design is column rank deficient so dropping 1 coef" so I just combine the levels as the model will do
levels(df$appearance)<-c("no","yes","yes")
df$quest <- factor(df$quest)
df$moral <- factor(df$moral)
df$dialog <- factor(df$dialog)
df$subject <- factor(df$subject)

q8 <- clmm(q8 ~ dialog + romance + romance_cut + friendship + (1|subject), data = df, link = "logit", Hess=TRUE,nAGQ=10L)

q8.mat <- expand.grid(
   c(0,q8$beta[1], q8$beta[2], q8$beta[3], q8$beta[4], q8$beta[5])
)

plot1<-plot.probabilities2(q8.mat, q8, c("none",
   "interactive dialogue",
   "romance modeling: some",
   "romance modeling: yes",
   "romance in cut-scenes",
   "friendship modeling"))
plot1

# U2, RDR & ACB: romance_cut: yes, romance: no, dialog: no, friendship: no
q8.mat.u2 <- expand.grid(subject = qnorm(0.95) * c(0, -1, 1) * q8$stDev,
    romance_cut=c(q8$beta[4])
)
q8.mat.me2 <- expand.grid(subject = qnorm(0.95) * c(0, -1, 1) * q8$stDev,
   romance_cut=c(q8$beta[4]),
   romance=c(q8$beta[3]),
   dialog=c(q8$beta[1]),
   friendship=c(q8$beta[5])
)

q8.mat.dehr <- expand.grid(subject = qnorm(0.95) * c(0, -1, 1) * q8$stDev,
   romance_cut=c(q8$beta[4]),
   dialog=c(q8$beta[1]),
   friendship=c(q8$beta[5])
)

q8.mat.esv<- expand.grid(subject = qnorm(0.95) * c(0, -1, 1) * q8$stDev,
   romance_cut=c(q8$beta[4]),
   romance=c(q8$beta[2]),
   dialog=c(q8$beta[1]),
   friendship=c(q8$beta[5])
)

q8.u2.sub<-subset(df, game=="U2" |game == "RDR" | game=="ACB")
q8.me2.sub<-subset(df, game=="ME2" | game=="DA2" | game=="DAO")
q8.dehr.sub<-subset(df, game=="DEHR")
q8.esv.sub<-subset(df, game=="ESV")

# add more game data comparisons for the poster
plot1<- plot.probabilities3(q8.mat.u2, q8, q8.u2.sub$q8, title="U2, RDR, ACB", ylim=.75)
plot2 <- plot.probabilities3(q8.mat.me2, q8, q8.me2.sub$q8, title="ME2, DAO, DA2", ylim=.75)
plot3 <- plot.probabilities3(q8.mat.dehr, q8, q8.dehr.sub$q8, title="DEHR", ylim=.75)
plot4 <- plot.probabilities3(q8.mat.esv, q8, q8.esv.sub$q8, title="ESV", ylim=.75)
grid.arrange(plot1, plot2, plot3, plot4, ncol=2)
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s