不知道大家有沒有玩過Gartic.io(你畫我猜)這款遊戲,我希望能做出類似的遊戲,計畫透過firebase做連線,目前已完成canvas,但卡在如何將canvas中的paths儲存至雲端,原本是打算使用Gson將path轉換成json後再上傳,但轉換的結果似乎與預期不符,轉換結果如下:
另外canvas的code如下:
private const val STROKE_WIDTH = 12f // has to be float
class CanvasView(c : Context,attrs: AttributeSet? = null) : View(c,attrs) {
private lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap
private val backgroundColor = ResourcesCompat.getColor(resources, R.color.white, null)
var drawColor = ResourcesCompat.getColor(resources, R.color.black, null)
val paint = Paint().apply {
color = drawColor
// Smooths out edges of what is drawn without affecting shape.
isAntiAlias = true
// Dithering affects how colors with higher-precision than the device are down-sampled.
isDither = true
style = Paint.Style.STROKE // default: FILL
strokeJoin = Paint.Join.ROUND // default: MITER
strokeCap = Paint.Cap.ROUND // default: BUTT
strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}
val paintFrame = Paint().apply {
color = drawColor
// Smooths out edges of what is drawn without affecting shape.
isAntiAlias = true
// Dithering affects how colors with higher-precision than the device are down-sampled.
isDither = true
style = Paint.Style.STROKE // default: FILL
strokeJoin = Paint.Join.ROUND // default: MITER
strokeCap = Paint.Cap.ROUND // default: BUTT
strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}
private var path = Path()
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f
private var currentX = 0f
private var currentY = 0f
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlop
private lateinit var frame: Rect
//redo
private val paths = ArrayList<Path>()
private val undonePaths = ArrayList<Path>()
private val colors = ArrayList<Int>()
private val undoColors = ArrayList<Int>()
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
super.onSizeChanged(width, height, oldWidth, oldHeight)
if (::extraBitmap.isInitialized) extraBitmap.recycle()
extraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
extraCanvas = Canvas(extraBitmap)
extraCanvas.drawColor(backgroundColor)
val inset = 20
frame = Rect(inset, inset, width - inset, height - inset)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
var i = 0
val resentColor = paint.color
for (Path in paths) {
paint.color = colors[i]
i ++
canvas.drawPath(Path, paint)
}
paint.color = resentColor
canvas.drawPath(path, paint)
canvas.drawRect(frame, paintFrame)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
motionTouchEventX = event.x
motionTouchEventY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> touchStart()
MotionEvent.ACTION_MOVE -> touchMove()
MotionEvent.ACTION_UP -> touchUp()
}
return true
}
private fun touchStart() {
undonePaths.clear()
undoColors.clear()
path.reset()
path.moveTo(motionTouchEventX, motionTouchEventY)
currentX = motionTouchEventX
currentY = motionTouchEventY
}
private fun touchMove() {
val dx = Math.abs(motionTouchEventX - currentX)
val dy = Math.abs(motionTouchEventY - currentY)
if (dx >= touchTolerance || dy >= touchTolerance) {
// QuadTo() adds a quadratic bezier from the last point,
// approaching control point (x1,y1), and ending at (x2,y2).
path.quadTo(currentX, currentY, (motionTouchEventX + currentX) / 2, (motionTouchEventY + currentY) / 2)
currentX = motionTouchEventX
currentY = motionTouchEventY
// Draw the path in the extra bitmap to cache it.
extraCanvas.drawPath(path, paint)
}
invalidate()
}
private fun touchUp() {
// Reset the path so it doesn't get drawn again.
//redo
path.lineTo(currentX, currentY)
paths.add(path)
colors.add(paint.color)
path = Path()
}
fun getPath() : ArrayList<Path>{
return paths
}
//redo
fun resetCanvasDrawing() {
path.reset() // Avoiding saving redo from Path()
paths.clear()
invalidate()
}
fun undoCanvasDrawing() {
if (paths.size > 0) {
undoColors.add(colors.removeAt(paths.size - 1))
undonePaths.add(paths.removeAt(paths.size - 1))
invalidate()
} else {
Toast.makeText(context, "nothing to undo", Toast.LENGTH_SHORT).show()
}
}
fun redoCanvasDrawing() {
if (undonePaths.size > 0) {
colors.add(undoColors.removeAt(undonePaths.size - 1))
paths.add(undonePaths.removeAt(undonePaths.size - 1))
invalidate()
} else {
Toast.makeText(context, "nothing to redo", Toast.LENGTH_SHORT).show()
}
}
}
我也有想過直接傳輸圖片就好,但圖片的傳輸量較大,希望還是可以避免。
請問有什麼方法可以儲存畫圖的路徑,或是Gartic.io即時傳輸筆跡是如何達成的,只要給我一點提示或方向即可,拜託大家了~